这里是关于自己看JS语言精粹函数与数组方面的笔记,记得并不全面,是一些关于自己不太清楚的点。以后随着学习也可以继续补充。
所谓编程,就是将一组需求分解成一组函数与数据结构(的技能)。
函数基础
1.对象字面量产生的对象连接到 Object.prototype;函数对象连接到Function.prototype(然后这个原型对象本身连接到Object.prototype)
2.调用一个函数会暂停当前函数的执行,传递控制权和参数给新的函数。除了声明时定义的形式参数,每个函数还接收两个附加的参数:this 和 arguments。 关于this的解释见 JS中的this总结
3.arguments 函数可以通过此参数访问所有它被调用时传递给它的参数列表,包括那些没有被分配给函数声明时定义的形式参数的多余参数。这样就可以编写一个无须指定参数个数的函数成为可能。
1 2 3 4 5 6 7 8
| var sum = function(){ var i,sum =0; for(i=0;i<arguments.length;i+=1){ sum+=arguments[i]; } return sum; } console.log(sum(1,2,3,4,5))
|
arguments只是一个类似数组的对象,只有一个length属性,但没有任何数组的方法。
4.调用一个函数会暂停当前函数的执行,传递控制权和参数给新的函数。当一个函数被调用时,它从第一个语句开始执行,并在遇到关闭函数的}结束,然后把控制权交还给调用该函数的程序。return 可提前返回。一个函数总会返回一个值,若没有指定返回值,则返回undefined。如果函数是通过new操作符进行调用的,且返回值不是一个对象,则返回this(该新对象)。
5.扩充功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Function.prototype.method = function (name,func){ if(!this.prototype[name]){ this.prototype[name] = func; } return this; } Number.method('integer',function(){ return Math[this < 0 ? 'ceil' : 'floor'](this); }) Sting.method('trim',function(){ return this.replace(/^\s+|\s$/g,''); })
|
递归
1.递归函数可以高效的操作树形结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var walk_the_DOM = function walk(node,func){ func(node); node = node.firstChild; while(node){ walk(node,func); node = node.nextSibling; } } var getElementsByAttribute = function(att,value){ var results = {}; walk_the_DOM(document.body,function(node){ var actual = node.nodeType ===1 && node.getAttribute(att); if(typeof actual === 'string' && (actual === value || typeof value !== 'string')){ results.push(node); } }) return results; }
|
2.尾递归 是一种在函数的最后执行递归调用语句的特殊形式的递归,这意味着如果一个函数返回自身递归调用的结果,那么调用的过程会被替换成一个循环。加速。
柯里化(Curry)
1.柯里化 也为 “局部套用”,是把多参数函数转换成一系列单参数函数并进行调用的技术。柯里化允许我们把函数与传递给它的参数相结合,产生出一个新的函数。
1 2
| var add1 = add.curry(1); console.log(add1(6));
|
js并没有curry方法.
1 2 3 4 5 6 7 8
| Function.method('curry',function(){ var slice =Array.prototype.slice, args = slice.apply(arguments), that = this; return function (){ return that.apply(null,args.concat(slice.apply(arguments))); } });
|
闭包
1.函数可以记住并访问所在的词法作用域,就产生了闭包,即使函数在当前词法作用域之外执行。
(* 词法作用域 是由写代码时将变量和块作用域写在哪里决定的,因此放词法分析器处理代码时会保持作用域不变,大部分情况如此)
1 2 3 4 5 6 7 8 9
| function foo(){ var a = 2; function bar(){ console.log(a); } return bar; } var baz = foo(); baz();
|
在baz函数执行时,foo函数的内部作用域依然存在,并没有被回收。bar()依然持有对该作用域的引用。这个函数在定义时的词法作用域以外的地方被调用,闭包使得函数可以继续访问定义时的此法作用域。无论通过何种手段将内部函数传递到所在的词法作用域之外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。
2.
1 2 3 4 5
| for(var i=1;i<5;i++){ setTimeout(function timer(){ console.log(i); },1000); }
|
尽管循环中的五个函数是在各个迭代中分别定义的,但是这些都被封闭在一个共享的全局作用域中,因此只有一个i. 因此需要更多的闭包作用域。
1 2 3 4 5 6 7
| for(var i=1;i<=5;i++){ (function(j){ setTimeout(function timer(){ console.log(j); },1000); })(i); }
|
在迭代内由于函数执行会为每个迭代都生成一个新的作用域,使得延迟函数的回调可以将新的作用域封闭在每个迭代内部。
1 2 3 4 5
| for(let i=1;i<5;i++){ setTimeout(function timer(){ console.log(i); },1000); }
|
let 使得变量每次迭代都会声明一次.
模块
1.用函数与闭包来构造模块,模块是一个提供接口却隐藏状态与实现的函数或者对象.
2.给String增加一个方法 deentityify 方法,用来寻找字符串中的html字符实体并把它们替换成对应的字符,这就需要在一个对象中保存字符实体的名字和它们对应的字符。
1 2 3 4 5 6 7 8 9 10 11 12 13
| String.method('deentityify',function(){ var entity = { quot:'"', lt:'<', gt:'>' }; return function(){ return this.place(/&([^&;]+)/g),function(a,b){ var r = entity[b]; return typeof r === 'string' ? r :a; } } }())
|
这个entity 对象若是放在deentityfy函数中,每次执行时都会有损耗,因为每次执行该函数的时候该字面量都会被求值一次。
3.每个模块都有一个外部的封闭函数,该函数必须至少被调用一次,每次调用都会创建一个新的模块实例。 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。
- 当只需要一个实例时,可以对这个模块进行简单的改进来实现单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var foo = (function cool(){ var something = "ss"; var another = [1,2,3]; function doSomething (){ console.log(something); } function doAnother (){ console.log(another.join("!")); } return { doSomething:doSomething, doAnother:doAnother } })(); foo.doSomething(); foo.doAnother();
|
数组
1.JS数组的length是没有上界的,不会发生越界错误。length属性的值是这个数组的最大整数属性名+1。并不一定等于数组里的属性个数。也可以设置length的值,设置更大的length不会给数组分配更多的空间,而把length设小将导致所有下标大于等于length的属性被删除。
2.判断一个对象是否为数组。
1 2 3
| var is_array = function (value){ return Object.prototype.toString.apply(value) === "[object Array]"; }
|
3.数组几个重要的方法
1 2 3
| array.join(separator); array.slice(start,end); array.splice(start,deleteCount,item...);
|
4.字符串几个重要方法
1 2
| string.slice(start,end); string.split(separator,limit);
|